package com.yimaxiaoerlang.rtc_lib;

import android.app.Activity;
import android.content.Context;
import android.media.AudioManager;
import android.util.Log;

import com.yimaxiaoerlang.module_signalling.YMRTMChannel;
import com.yimaxiaoerlang.module_signalling.core.YMRTMChannelListener;
import com.yimaxiaoerlang.module_signalling.core.YMRTMJoinChannelCallback;
import com.yimaxiaoerlang.module_signalling.core.YMRTMJoinChannelStatusCode;

import org.json.JSONException;
import org.json.JSONObject;
import org.webrtc.AudioSource;
import org.webrtc.AudioTrack;
import org.webrtc.Camera1Enumerator;
import org.webrtc.CameraVideoCapturer;
import org.webrtc.DefaultVideoDecoderFactory;
import org.webrtc.DefaultVideoEncoderFactory;
import org.webrtc.EglBase;
import org.webrtc.IceCandidate;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStream;
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.SessionDescription;
import org.webrtc.SurfaceTextureHelper;
import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoSource;
import org.webrtc.VideoTrack;
import org.webrtc.audio.AudioDeviceModule;
import org.webrtc.audio.JavaAudioDeviceModule;

import java.util.ArrayList;
import java.util.HashMap;


public class YMVideoRoomHelper implements YMVideoHeplerOperation {
    private Activity context;
    private String uid;
    private YMRTMChannel channel;
    private YMVideoRoomHelperLinstener listener;


    private final String TAG = YMVideoRoomHelper.class.getSimpleName();
    private final String SDP = "sdp";
    private final String CANDIDATE = "candidate";
    private final String SOCKETID = "socketId";
    private final String ID = "id";
    private final String LABEL = "label";
    private final String OFFER = "offer";
    private final String ANSWER = "answer";
    private final String EVENTNAME = "eventName";


    //存储打洞服务列表
    private ArrayList<PeerConnection.IceServer> iceServers = new ArrayList<>();

    //存储链接map
    private HashMap<String, PeerConnection> peerConnectionMap = new HashMap<>();

    // remote surfaceview
    private HashMap<String, SurfaceViewRenderer> surfaceViewMap = new HashMap<>();


    private EglBase.Context eglBaseContext;
    private PeerConnectionFactory peerConnectionFactory;
    private MediaStream mediaStream;
    private AudioTrack _localAudioTrack;
    private AudioSource audioSource;
    private CameraVideoCapturer videoCapturer;
    private final String AUDIO_TRACK_ID = "ARDAMSa0";
    private SurfaceViewRenderer localSurfaceView;
    private AudioManager audioManager;


    public YMVideoRoomHelper(Activity context, String uid, YMRTMChannel channel, YMVideoRoomHelperLinstener listener) {
        this.context = context;
        this.uid = uid;
        this.channel = channel;
        this.listener = listener;
        init();
    }

    private void init() {
        PeerConnection.IceServer.Builder builder = PeerConnection.IceServer.builder(YMRLClient.getIceServerUrl());
        builder.setUsername("user");
        builder.setPassword("Yingjiekeji0532");
        PeerConnection.IceServer iceServer = builder.createIceServer();
        iceServers.add(iceServer);
        // create PeerConnectionFactory
        PeerConnectionFactory.initialize(
                PeerConnectionFactory.InitializationOptions
                        .builder(context)
                        .createInitializationOptions()
        );

        eglBaseContext = EglBase.create().getEglBaseContext();
        PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
        DefaultVideoEncoderFactory defaultVideoEncoderFactory = new DefaultVideoEncoderFactory(eglBaseContext, true, true);
        DefaultVideoDecoderFactory defaultVideoDecoderFactory = new DefaultVideoDecoderFactory(eglBaseContext);
        AudioDeviceModule audioDeviceModule = JavaAudioDeviceModule.builder(context).createAudioDeviceModule();
        peerConnectionFactory = PeerConnectionFactory.builder()
                .setOptions(options)
                .setVideoEncoderFactory(defaultVideoEncoderFactory)
                .setVideoDecoderFactory(defaultVideoDecoderFactory)
                .setAudioDeviceModule(audioDeviceModule)
                .createPeerConnectionFactory();

        audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);

    }

    public void join() {
        channel.joinChannel(new YMRTMJoinChannelCallback() {
            @Override
            public void completion(YMRTMJoinChannelStatusCode code) {
                if (code == YMRTMJoinChannelStatusCode.Success) {
//                    initLocal();
                }
            }
        });
        channel.setChannelListener(new YMRTMChannelListener() {
            @Override
            public void onReceiveMessage(String peerId, String msg) {
                didReciveMessage(msg, peerId);
            }

            @Override
            public void onMemberJoined(String peerId) {
                didMemberJoin(peerId);
            }

            @Override
            public void onMemberLeaved(String peerId) {
                didMemberLeave(peerId);
            }
        });
    }

    public void leave() {
        channel.leaveChannel(null);

        for (String key : peerConnectionMap.keySet()) {
            PeerConnection peerConnection = peerConnectionMap.get(key);
            peerConnection.removeStream(mediaStream);
            peerConnection.dispose();
        }
        if (videoCapturer != null) {
            try {
                videoCapturer.stopCapture();
                videoCapturer.dispose();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        if (mediaStream != null) {
            try {
                mediaStream.dispose();
            } catch (Exception e) {

            }
        }

        if (localSurfaceView != null) {
            localSurfaceView.release();
        }
        if (peerConnectionFactory != null) {
            peerConnectionFactory.dispose();
        }
        peerConnectionMap.clear();
        peerConnectionFactory = null;
    }


    /**
     * 处理消息
     */
    private void didReciveMessage(String msg, String meberId) {
        Log.e(TAG, "didReciveMessage(" + meberId + "): " + msg);
        if (msg.contains(EVENTNAME)) {
            Log.e(TAG, "收到视频消息 -> " + msg);
            JSONObject data = null;
            try {
                data = new JSONObject(msg);
                String to = data.optString(SOCKETID);
                Log.e(TAG, "接收者$to" + to);
                if (!to.equals(uid)) return;
                String type = data.optString(EVENTNAME);
                Log.e(TAG, "didReciveMessage: TYPE -> " + type);
                JSONObject finalData = data;
                context.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (type.equals(OFFER)) {
                            onOfferReceived(finalData, meberId);
                        } else if (type.equals(ANSWER)) {
                            onAnswerReceived(finalData, meberId);
                        } else if (type.equals(CANDIDATE)) {
                            onIceCandidateReceived(finalData, meberId);
                        }
                    }
                });

            } catch (JSONException e) {
                e.printStackTrace();
            }
        } else {
            if (listener != null) {
                listener.didReciveOtherMessage(msg, meberId);

            }
        }
    }

    /**
     * 初始化本地
     */
    public void initLocal() {
        localSurfaceView = createSurfaceView(true);
        SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create("CaptureThread", eglBaseContext);

        // create VideoCapturer 本地预览
        videoCapturer = createCameraCapturer(true);
        VideoSource videoSource = peerConnectionFactory.createVideoSource(videoCapturer.isScreencast());
        if (videoCapturer != null) {
            videoCapturer.initialize(
                    surfaceTextureHelper,
                    context,
                    videoSource.getCapturerObserver()
            );
            videoCapturer.startCapture(480, 640, 30);
        }


        // create VideoTrack
        VideoTrack videoTrack = peerConnectionFactory.createVideoTrack("ARDAMSv0", videoSource);
//        val videoTrack = peerConnectionFactory!!.createVideoTrack("100", videoSource)
//        // display in localView
        videoTrack.addSink(localSurfaceView);

        mediaStream = peerConnectionFactory.createLocalMediaStream("ARDAMS");
        //        mediaStream = peerConnectionFactory.createLocalMediaStream("mediaStream");
        audioSource = peerConnectionFactory.createAudioSource(createAudioConstraints());

        _localAudioTrack = peerConnectionFactory.createAudioTrack(
                AUDIO_TRACK_ID,
                audioSource
        );

        mediaStream.addTrack(_localAudioTrack);
        mediaStream.addTrack(videoTrack);
        listener.onLocalJoin(localSurfaceView);
    }

    /**
     * 当用户加入
     */
    private void didMemberJoin(String meberId) {
        Log.e(TAG, "didMemberJoin: " + meberId);
        PeerConnection peerConnection = getOrCreatePeerConnection(meberId);
        peerConnection.createOffer(new YMSdpAdapter("createOfferSdp:$meberId") {
            @Override
            public void onCreateSuccess(SessionDescription sessionDescription) {
                super.onCreateSuccess(sessionDescription);
                peerConnection.setLocalDescription(
                        new YMSdpAdapter("setLocalSdp:$meberId"),
                        sessionDescription
                );
                //发送offer
                sendOffer(sessionDescription, meberId);

            }
        }, new MediaConstraints());
    }

    /**
     * 当用户离开
     */
    private void didMemberLeave(String meberId) {
        SurfaceViewRenderer view = surfaceViewMap.get(meberId);
        PeerConnection connecttion = peerConnectionMap.get(meberId);
        if (connecttion != null) {
            connecttion.removeStream(mediaStream);
            connecttion.dispose();
            peerConnectionMap.remove(meberId);
        }
        if (listener != null) {
            listener.onRemoteLeave(view, meberId);
        }
        if (view != null) {
            view.release();
            surfaceViewMap.remove(meberId);
        }
    }


    /**
     * 发送offer
     */
    private void sendOffer(SessionDescription sdp, String meberId) {
        JSONObject jo = new JSONObject();
        try {
            jo.put(EVENTNAME, OFFER);
            jo.put(SDP, sdp.description);
            jo.put(SOCKETID, meberId);
//            channel.sendMessage(jo.toString(), object : RTMSendChannelCallback {
//                override fun completion(rtmSendChannelMessageStatusCode: RTMSendChannelMessageStatusCode) {}
//            })
            channel.sendVoIPMessage(jo.toString(), null);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }


    /**
     * 发送 answer
     */
    private void sendAnswer(SessionDescription sdp, String meberId) {
        Log.e(TAG, "sendAnswer: 发送ANSWER");
        JSONObject jo = new JSONObject();
        try {
            jo.put(EVENTNAME, ANSWER);
            jo.put(SDP, sdp.description);
            jo.put(SOCKETID, meberId);
//            channel.sendMessage(jo.toString(), object : RTMSendChannelCallback {
//                override fun completion(rtmSendChannelMessageStatusCode: RTMSendChannelMessageStatusCode) {}
//            })
            channel.sendVoIPMessage(jo.toString(), null);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    /**
     * 收到offer
     */
    private void onOfferReceived(JSONObject data, String meberId) {
        Log.e(TAG, "onOfferReceived: 收到OFFER");
        context.runOnUiThread(new Runnable() {

            @Override
            public void run() {
                PeerConnection peerConnection = getOrCreatePeerConnection(meberId);
                peerConnection.setRemoteDescription(
                        new YMSdpAdapter("setRemoteSdp:$meberId"),
                        new SessionDescription(
                                SessionDescription.Type.OFFER,
                                data.optString(SDP)
                        )
                );
                peerConnection.createAnswer(new YMSdpAdapter("localAnswerSdp") {
                    @Override
                    public void onCreateSuccess(SessionDescription sdp) {
                        super.onCreateSuccess(sdp);
                        peerConnectionMap.get(meberId)
                                .setLocalDescription(new YMSdpAdapter("setLocalSdp:$meberId"), sdp);
                        sendAnswer(sdp, meberId);
                    }
                }, new MediaConstraints());
            }


        });
    }

    /**
     * 收到answer
     */
    private void onAnswerReceived(JSONObject data, String meberId) {
        Log.e(TAG, "onAnswerReceived: 收到ANSWER");
        PeerConnection peerConnection = getOrCreatePeerConnection(meberId);
        peerConnection.setRemoteDescription(
                new YMSdpAdapter("setRemoteSdp:$meberId"),
                new SessionDescription(SessionDescription.Type.ANSWER, data.optString(SDP))
        );
    }

    /**
     * 发送candidate
     */
    private void sendCandidate(IceCandidate iceCandidate, String meberId) {
        JSONObject jo = new JSONObject();
        try {
            jo.put(EVENTNAME, CANDIDATE);
            jo.put(LABEL, iceCandidate.sdpMLineIndex);
            jo.put(ID, iceCandidate.sdpMid);
            jo.put(CANDIDATE, iceCandidate.sdp);
            jo.put(SOCKETID, meberId);

//            socket.emit("message", jo);
//            channel.sendMessage(jo.toString(), object : RTMSendChannelCallback {
//                override fun completion(rtmSendChannelMessageStatusCode: RTMSendChannelMessageStatusCode) {}
//            })
            channel.sendVoIPMessage(jo.toString(), null);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    /**
     * 收到candidate
     */
    private void onIceCandidateReceived(JSONObject data, String meberId) {
        Log.e(TAG, "onIceCandidateReceived: 收到CANDIDATE");
        PeerConnection peerConnection = getOrCreatePeerConnection(meberId);
        peerConnection.addIceCandidate(
                new IceCandidate(
                        data.optString(ID),
                        data.optInt(LABEL),
                        data.optString(CANDIDATE)
                )
        );
    }

    /**
     * 获取链接
     */

    private synchronized PeerConnection getOrCreatePeerConnection(String socketId) {
        Log.e(TAG, "socket ID $socketId" + socketId);
        PeerConnection peerConnection = peerConnectionMap.get(socketId);
        if (peerConnection != null) {

            return peerConnection;
        }
        peerConnection =
                peerConnectionFactory.createPeerConnection(iceServers, new YMPeerConnectionAdapter(
                        "PC:$socketId" + socketId
                ) {
                    @Override
                    public void onIceCandidate(IceCandidate iceCandidate) {
                        super.onIceCandidate(iceCandidate);
                        //  发送candidate
                        Log.e("zgj", "发送Candidate   id${socketId}" + socketId);
                        sendCandidate(iceCandidate, socketId);
                    }


                    @Override
                    public void onAddStream(MediaStream mediaStream) {
                        super.onAddStream(mediaStream);

                        // 渲染
                        context.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                VideoTrack remoteVideoTrack = mediaStream.videoTracks.get(0);
                                SurfaceViewRenderer remoteView = createSurfaceView(false);
                                remoteVideoTrack.addSink(remoteView);
                                surfaceViewMap.put(socketId, remoteView);
                                if (listener != null) {
                                    listener.onRemoteJoin(remoteView, socketId);
                                }
                            }
                        });

                    }
                });
        peerConnection.addStream(mediaStream);
        peerConnectionMap.put(socketId, peerConnection);
        return peerConnection;
    }

    /**
     * 创建surfaceview
     */
    private SurfaceViewRenderer createSurfaceView(Boolean local) {
        SurfaceViewRenderer surfaceViewRenderer = new SurfaceViewRenderer(context);
        surfaceViewRenderer.setMirror(local);
        surfaceViewRenderer.init(eglBaseContext, null);
        return surfaceViewRenderer;
    }

    private CameraVideoCapturer createCameraCapturer(Boolean isFront) {
        Camera1Enumerator enumerator = new Camera1Enumerator(false);
        String[] deviceNames = enumerator.getDeviceNames();

        // First, try to find front facing camera

        for (String deviceName : deviceNames) {

            if (isFront ? enumerator.isFrontFacing(deviceName) : enumerator.isBackFacing(deviceName)) {
                CameraVideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);
                if (videoCapturer != null) {
                    return videoCapturer;
                }
            }
        }

        return null;
    }

    //**************************************各种约束******************************************/
    private final String AUDIO_ECHO_CANCELLATION_CONSTRAINT = "googEchoCancellation";
    private final String AUDIO_AUTO_GAIN_CONTROL_CONSTRAINT = "googAutoGainControl";
    private final String AUDIO_HIGH_PASS_FILTER_CONSTRAINT = "googHighpassFilter";
    private final String AUDIO_NOISE_SUPPRESSION_CONSTRAINT = "googNoiseSuppression";


    /**
     * 配置音频参数
     */
    private MediaConstraints createAudioConstraints() {
        MediaConstraints audioConstraints = new MediaConstraints();
        audioConstraints.mandatory.add(
                new MediaConstraints.KeyValuePair(AUDIO_ECHO_CANCELLATION_CONSTRAINT, "true")
        );
        audioConstraints.mandatory.add(
                new MediaConstraints.KeyValuePair(AUDIO_AUTO_GAIN_CONTROL_CONSTRAINT, "false")
        );
        audioConstraints.mandatory.add(
                new MediaConstraints.KeyValuePair(AUDIO_HIGH_PASS_FILTER_CONSTRAINT, "false")
        );
        audioConstraints.mandatory.add(
                new MediaConstraints.KeyValuePair(AUDIO_NOISE_SUPPRESSION_CONSTRAINT, "true")
        );
        return audioConstraints;
    }

    /**
     * 切换摄像头
     */
    @Override
    public void switchCamera() {
        if (videoCapturer == null) return;
        videoCapturer.switchCamera(new CameraVideoCapturer.CameraSwitchHandler() {
            @Override
            public void onCameraSwitchDone(boolean b) {
                Log.e(TAG, "摄像头切换成功$p0" + b);
            }

            @Override
            public void onCameraSwitchError(String s) {
                Log.e(TAG, "摄像头切换失败$p0" + s);
            }

        });
    }


    /**
     * 打开摄像头
     */
    @Override
    public void openCamera(Boolean open) {
        if (!open) {
            if (videoCapturer != null) {
                try {
                    videoCapturer.stopCapture();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } else {
            if (videoCapturer != null) {
                videoCapturer.startCapture(480, 640, 30);
            }
        }
    }

    /**
     * 打开麦克风
     */

    @Override
    public void openMic(Boolean open) {
        if (_localAudioTrack != null) {
            _localAudioTrack.setEnabled(open);
        }
    }


    private int currVolume = 66;

    /**
     * 听筒扬声器切换
     *
     * @return
     */
    @Override
    public Boolean openSpeaker() {

        if (!audioManager.isSpeakerphoneOn()) {
            audioManager.setSpeakerphoneOn(true);
        } else {
            audioManager.setSpeakerphoneOn(false);//关闭扬声器
            audioManager.setRouting(
                    AudioManager.MODE_NORMAL,
                    AudioManager.ROUTE_EARPIECE,
                    AudioManager.ROUTE_ALL
            );
//            setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
            //把声音设定成Earpiece（听筒）出来，设定为正在通话中
            audioManager.setMode(AudioManager.MODE_IN_CALL);
        }
        return audioManager.isSpeakerphoneOn();

    }

}
